using System;
using System.Reflection;
using System.Collections;
using System.Diagnostics;
using System.IO;

namespace Log
{
    class LogString
    {

        private const int LOG_MAX_FILE_SIZE = 2097152;
        private const int LOG_MAX_FILE_COUNT = 256;

        private string  m_strPath       =   string.Empty;
        private string  m_strName       =   string.Empty;
        public  string  m_strLogPath    =   string.Empty;
        private string  m_strLog        =   string.Empty;

        public delegate void LogUpdateDelegate();
        public event LogUpdateDelegate OnLogUpdate;

        private static Hashtable m_LogsTable = new Hashtable();

        // Generate the log file name
        //
        private string FileName { get { return m_strLogPath + m_strName + ".log"; } }

        // Constructor
        private LogString()
        {   try
            {
                Module mod = System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0];
                m_strPath = Path.GetDirectoryName( mod.FullyQualifiedName );
                m_strName = Path.GetFileNameWithoutExtension( mod.FullyQualifiedName );
                m_strLogPath = m_strPath + "\\" + m_strName + "_Logs\\";
                Directory.CreateDirectory( m_strLogPath );
            }
            catch ( Exception e )
            {
                m_strLogPath = string.Empty;
                Debug.WriteLine("The Log Directory Creation failed: {0}", e.ToString());
            }

        }

        // Check for log lenght and rename if needed
        //
        private void CheckFileList()
        {
            DateTime dt = DateTime.Now;
            String FileNameNew = String.Empty;
            FileNameNew = m_strLogPath + m_strName + dt.ToString( "_yyyyMMddHHmmss" ) + ".log";
            DirectoryInfo dir = new DirectoryInfo( m_strLogPath );
            FileInfo[] fi = dir.GetFiles( m_strName + "*.log", SearchOption.TopDirectoryOnly );

            try 
            {
                // Ensure that the target does not exist.
                if( File.Exists( FileNameNew ) )    
                    File.Delete( FileNameNew );

                // Move the file.
                File.Move( FileName, FileNameNew );
            } 
            catch( Exception e ) 
            {
                Debug.WriteLine( "The process failed: {0}", e.ToString() );
            }

            //deletes the redundant file
            if( fi.Length >= LOG_MAX_FILE_COUNT )
            {
                do
                {
                    try
                    {
                        // Ensure that the target does not exist.
                        if( File.Exists( m_strLogPath + fi[0].Name ) )
                        {
                            if( !fi[0].Name.Equals( FileName ) )
                                File.Delete( m_strLogPath + fi[0].Name );
                        }
                    }
                    catch ( Exception e )
                    {
                        Debug.WriteLine( "The process failed: {0}", e.ToString() );
                    }

                    fi = dir.GetFiles( m_strName + "*.log", SearchOption.TopDirectoryOnly );
                }
                while( fi.Length >= LOG_MAX_FILE_COUNT );
            }
        }

        // Write the log file. Delete existing first
        private void WriteLog()
        {
            if ( Settings.Settings.WriteLog.ToString()=="True" )
            {
                FileInfo fi = new FileInfo( FileName );
                lock ( m_strLog )        // lock resource
                {
                    if ( File.Exists( FileName ) )
                        if ( fi.Length > LOG_MAX_FILE_SIZE )
                            CheckFileList();
                   
                    using ( StreamWriter sw = File.AppendText( FileName ) )
                    {
                        sw.Write( m_strLog + "\r\n" );         // write entire contents
                        sw.Close();
                    }
                }
            }
         }

        // Access to named LogString instances.      
        public static LogString GetLogString( string name )
        {
            // If it exists, return the existing log.
            if ( m_LogsTable.ContainsKey( name ) ) return ( LogString )m_LogsTable[name];

            // Create and return a new log.
            LogString rv = new LogString();
            m_LogsTable.Add( name, rv ); // add to table
            return rv;
        }

        // Get the logging string. This returns the current log string.      
        public string Log
        {
            get
            {
                lock ( m_strLog )  // lock the resource
                {
                    return m_strLog;
                }
            }
        }

       public void LogCreate()
        {
            try
            {
                // Determine whether the directory exists.
                if ( Directory.Exists( m_strLogPath ) )
                {
                    Debug.WriteLine( m_strLogPath + " path exists already." );
                    return;
                }

                // Try to create the directory.
                DirectoryInfo di = Directory.CreateDirectory( m_strLogPath );
                string message = string.Format("The directory " + m_strLogPath + " was created successfully at {0}.", Directory.GetCreationTime(m_strLogPath));
                Debug.WriteLine( message );
            }
            catch ( Exception e )
            {
                Debug.WriteLine( m_strLogPath + " - The process failed: {0}", e.ToString() );
            }
            finally { }
        }

        // Clients can get update callbacks. The LogUpdateDelegate will be 
        // called whenever a new entry is added to a log.       
        public void Add( string str )
        {
            string toadd = "";

            DateTime dt = DateTime.Now;
            toadd = string.Format( "{0:d2}-{1:d2}-{2:d4} {3:d2}:{4:d2}:{5:d2}.{6:d3}\t",  dt.Day, dt.Month, dt.Year, dt.Hour, dt.Minute, dt.Second, dt.Millisecond );
            // Add the string
            toadd += str;

            lock (m_strLog) // lock resource 
            {
                m_strLog = toadd;
                WriteLog();

            }
            if (OnLogUpdate != null) OnLogUpdate();
                        
        }
    }
}
